﻿using System.Reflection;
using PostSharp.CodeModel;
using PostSharp.Laos.Weaver;

namespace Weaver
{
/// <summary>
/// Adds the field to a class.
/// </summary>
public class AddFieldWeaver : TypeLevelAspectWeaver
{
   #region Constructors

   public AddFieldWeaver(string fieldTypeName, string fieldName, string associationName)
   {
      FieldTypeName = fieldTypeName;
      FieldName = fieldName;
      AssociationName = associationName;
   }

   #endregion

   #region Fields

   private ITypeSignature fieldType;

   #endregion

   #region Methods

   /// <summary>
   /// This method does the work.
   /// </summary>
   public override void Implement()
   {
      // This is what creating a field looks like in PostSharp:
      // We create a FieldDefDeclaration and give it a name, set its attributes
      // to make it public and then set its type.
      var newField = new FieldDefDeclaration
                                {
                                   Name = FieldName, 
                                   Attributes = FieldAttributes.Public, 
                                   FieldType = FieldType 
                                };

      // Then we just add the field to the TypeDefDeclaration supplied for us by PostSharp.
      ((TypeDefDeclaration) TargetType).Fields.Add(newField);

      // Now we create an attribute using a utility function and 
      // then just add it to our new field.  
      var attribute = Utils.CreateAssociationAttribute(Task.Project.Module, AssociationName);
      newField.CustomAttributes.Add(attribute);
   }

   #endregion

   #region Properties

   public string AssociationName { get; set; }

   /// <summary>
   /// Gets the type linked by the collection.
   /// </summary>
   /// <value>The type of the linked.</value>
   public ITypeSignature FieldType
   {
      get
      {
         if (fieldType == null)
         {
            fieldType = Task.Project.Module.FindType(FieldTypeName, BindingOptions.Default);
         }
         return fieldType;
      }
   }

   public string FieldTypeName { get; set; }
   private string FieldName { get; set; }

   #endregion
}
}